module ysyx_050369_csr_reg (
    input           clk,
    input           rst,
    input           csr_wen,
    input [11:0]    csr_waddr,
    input [63:0]    csr_wdata,
    input [11:0]    csr_raddr,
    output reg[63:0]csr_rdata,
    input [31:0]    i_ex_nxpc,
    input           i_pc_stop,
    input           mret_flag,
    input           i_ctime,
    input           i_cmsip,
    input           i_cext,
    input           i_ecall_flag,
    input [31:0]    i_ecall_pc,
    output[31:0]    o_metvc,
    output[31:0]    o_mepc,
    output          timer_valid,
    output          raise_intr
    
);
`define ysyx_050369_MEIP   11
`define ysyx_050369_MSIP   3
`define ysyx_050369_MTIP   7

    wire        ctime;
    wire        cmsip;
    wire        cext;
    reg [63:0] mepc;
    reg [63:0] mcause;
    reg [63:0] mstatus;
    reg [63:0] metvc;
    reg [15:0] mie;
    reg [15:0] mip;
    reg [31:0] ex_nxpc_r;
    always @(posedge clk) begin
        if (rst)  ex_nxpc_r <= 'b0;
        else      ex_nxpc_r <= (i_ex_nxpc[31:4]==0)?ex_nxpc_r:i_ex_nxpc;
    end
    always @(posedge clk) begin
        if (rst) begin
            mstatus <= 64'ha00001800;
            mcause  <= 'b0;
            mepc    <= 'b0;
            metvc   <= 'b0;
            mie     <= 'b0;
            mip     <= 'b0;
        end
        else if(csr_wen) begin
            case (csr_waddr)
                `ysyx_050369_CSR_MEPC:    mepc    <= csr_wdata;
                `ysyx_050369_CSR_MCAUSE:  mcause  <= csr_wdata;
                `ysyx_050369_CSR_MSTATUS: mstatus <= csr_wdata;
                `ysyx_050369_CSR_MTVEC:   metvc   <= csr_wdata;
                `ysyx_050369_MIE:         mie     <= csr_wdata[15:0];     
                `ysyx_050369_MIP:         mip     <= csr_wdata[15:0];
                default: begin end
            endcase
        end
        else begin
            if (i_ctime || i_cmsip || i_cext ) begin
                mip <= {mip[15:12],i_cext,mip[10:8],i_ctime,mip[6:4],i_cmsip,mip[2:0]};
            end
            else begin
                mip <= 'b0;
            end
            if ((raise_intr || i_ecall_flag) && ~i_pc_stop ) begin
                mepc    <=  i_ecall_flag?{32'b0,i_ecall_pc}:{32'b0,i_ecall_pc[31:4]==0?ex_nxpc_r:i_ex_nxpc};
                case ({i_ecall_flag , ctime , cmsip , cext})
                    4'b1000: mcause <= 64'd11;
                    4'b0100: mcause <= 64'h8000_0000_0000_0007;
                    4'b0010: mcause <= 64'h8000_0000_0000_0003;
                    4'b0001: mcause <= 64'h8000_0000_0000_000b;
                    default: mcause <= 64'h0;
                endcase
                mstatus[7] <= mstatus[3];
                mstatus[3] <= 1'b0 ;
            end
            else if (mret_flag) begin
                mstatus[3] <= mstatus[7];
                mstatus[7] <= 1'b1 ;
            end

        end 
    end
    always @(*) begin
        case (csr_raddr)
            `ysyx_050369_CSR_MSTATUS:csr_rdata = mstatus    ;
            `ysyx_050369_CSR_MTVEC  :csr_rdata = metvc      ;
            `ysyx_050369_CSR_MEPC   :csr_rdata = mepc       ;
            `ysyx_050369_CSR_MCAUSE :csr_rdata = mcause     ;
            `ysyx_050369_MIE        :csr_rdata = {48'b0,mie}; 
            `ysyx_050369_MIP        :csr_rdata = {48'b0,mip};
            default: csr_rdata =64'b0;
        endcase
    end

    assign timer_valid = mstatus[3] & mie[`ysyx_050369_MTIP];
    assign o_metvc = metvc[31:0];
    assign o_mepc  = mepc[31:0];
    // assign o_mstatus = mstatus;
    assign ctime      = mip[`ysyx_050369_MTIP] && mie[`ysyx_050369_MTIP];//定时中断
    assign cmsip      = mip[`ysyx_050369_MSIP] && mie[`ysyx_050369_MSIP];
    assign cext       = mip[`ysyx_050369_MEIP] && mie[`ysyx_050369_MEIP];//外部终端
    assign raise_intr =  (ctime | cmsip | cext) && mstatus[3]&& ~(csr_wen && (csr_waddr==`ysyx_050369_CSR_MSTATUS) && (csr_wdata[3] == 0));
endmodule